package com.blue.fish.tiny.lexer;

import com.blue.fish.tiny.common.AlphabetHelper;
import com.blue.fish.tiny.common.PeekIterator;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

/**
 * @author QingFan
 * @version 1.0.0
 * @date 2023年01月28日 20:30
 */
public class Lexer {

    public List<Token> analyze(PeekIterator<Character> it) throws LexicalException {
        var tokens = new ArrayList<Token>();

        while (it.hasNext()) {
            char c = it.next();

            if (c == 0) {
                break;
            }
            char lookahead = it.peek();

            if (c == ' ' || c == '\n') {
                continue;
            }

            // 删除注释
            if (c == '/') {
                if (lookahead == '/') {
                    while (it.hasNext() && (c = it.next()) != '\n') {
                    }

                    continue;
                } else if (lookahead == '*') {
                    it.next();//多读一个* 避免/*/通过
                    boolean valid = false;
                    while (it.hasNext()) {
                        char p = it.next();
                        if (p == '*' && it.peek() == '/') {
                            it.next();
                            valid = true;
                            break;
                        }
                    }
                    if (!valid) {
                        throw new LexicalException("comments not match");
                    }
                    continue;
                }
            }

            if (c == '{' || c == '}' || c == '(' || c == ')') {
                tokens.add(new Token(TokenType.BRACKET, c + ""));
                continue;
            }

            if (c == '"' || c == '\'') {
                it.putBack();
                tokens.add(Token.makeString(it));
                continue;
            }

            if (AlphabetHelper.isLetter(c)) {
                it.putBack();
                tokens.add(Token.makeVarOrKeyword(it));
                continue;
            }


            if (AlphabetHelper.isNumber(c)) {
                it.putBack();
                tokens.add(Token.makeNumber(it));
                continue;
            }


            if ((c == '+' || c == '-' || c == '.') && AlphabetHelper.isNumber(lookahead)) {
                var lastToken = tokens.size() == 0 ? null : tokens.get(tokens.size() - 1);

                if (lastToken == null || !lastToken.isValue() || lastToken.isOperator()) {
                    it.putBack();
                    tokens.add(Token.makeNumber(it));
                    continue;
                }
            }

            if (AlphabetHelper.isOperator(c)) {
                it.putBack();
                tokens.add(Token.makeOp(it));
                continue;
            }

            throw new LexicalException(c);
        } // end while
        return tokens;
    }

    public List<Token> analyze(Stream<Character> stream) throws LexicalException {
        PeekIterator<Character> iterator = new PeekIterator<>(stream, (char) 0);
        return analyze(iterator);
    }
}
